fix(runtime): propagate session permissions to background agents and skills#3490
fix(runtime): propagate session permissions to background agents and skills#3490Piyush0049 wants to merge 3 commits into
Conversation
…skills This removes the hardcoded ToolsApproved bypass and ensures background tasks inherit the Allow/Deny/Ask permission configuration from their parent session. When tools fall back to 'Ask' in a background non-interactive context, the dispatcher correctly auto-denies them.
dgageot
left a comment
There was a problem hiding this comment.
Thanks for tackling this — inheriting session permissions instead of a blanket bypass is the right end state, and this closes a real enforcement hole where session-level allow/deny rules silently vanished in every sub-session. A few things need resolution before merge though.
Blocking
🔴 Data race: shared *PermissionsConfig pointer
pkg/runtime/agent_delegation.go:495 stores the same pointer (params.ParentSession.Permissions) on the child session. The "always allow this tool" resume path mutates sess.Permissions.Allow (pkg/runtime/toolexec/dispatcher.go:803-808) under a per-dispatcher mutex, while a background sub-session runs on a detached goroutine reading the same slices under a different dispatcher's mutex. That's a genuine data race.
Fix: deep-copy in newSubSession (or inside WithPermissions) — clonePermissionsConfig in pkg/session/branch.go:322 already does exactly this.
🔴 Unconditional back-propagation to parent
Because of the shared pointer, an "always allow tool X" approval inside a transfer/skill child mutates the parent's permissions immediately — even when the sub-session ends in error. This breaks runForwarding's success-only propagation invariant. Cloning fixes this too; if back-propagation is desired, it should be explicit on the success path.
Needs a decision
🟠 Behavior regression for run_background_agent
Before: background agents ran with ToolsApproved: true. After: in a default interactive session, any non-read-only tool call falls through to askUser, which auto-denies in non-interactive sessions (dispatcher.go:656-658) — background agents become effectively read-only unless in YOLO mode or with allow rules. The old comment described the blanket approval as a deliberate trade-off (approving run_background_agent itself was the consent gate). Is the new default the intended posture? Either way, it needs to be documented loudly.
🟠 Stale docs
docs/tools/background-agents/index.md:33 still claims "Tools run by the sub-agent are pre-approved…" — now false.
Should add
🟡 Test coverage
A security-sensitive change ships with zero test changes. Suggested additions in pkg/runtime/agent_delegation_test.go:
newSubSessionappliescfg.Permissions(and clone isolation after the fix)RunAgentinherits parentToolsApproved/PermissionsRunSkillFork/handleTaskTransferpropagatePermissions
Minor
- The
if cfg.Permissions != nilguard innewSubSessionbecomes redundant with a nil-safe clone helper — drop it. RunAgentreadsparams.ParentSession.ToolsApprovedfrom a background goroutine while the parent's dispatcher may write it — pre-existing unsynchronized bool read, worth fixing while touching this code.
What's good
- Session permission inheritance in
transfer_taskand skill forks is a real correctness/security win. - The rewritten
RunAgentcomment accurately describes the non-interactive auto-deny path. - Checker ordering (session-level first, then team) gives inherited rules correct precedence in children.
Verified on the branch: go build ./... ✅, go test ./pkg/runtime/... ./pkg/session/... ✅, go test -race ./pkg/runtime ✅, task lint ✅ (the race isn't surfaced because no test exercises the concurrent shared-permissions scenario).
|
Okay, I would fix this according to the feedback. |
|
dgageot I've pushed an update addressing all the review feedback. Summary of changes
The tests fully run locally, and all paths are fully isolated and green. |
39713be to
08fe4e6
Compare
|
I force-pushed to fix the linting errors caught by |
Overview
This PR resolves an issue where background agents and
run_skillsub-sessions were bypassing session-level permission rules by relying on a hardcodedToolsApproved: trueflag.Changes
Permissions: params.ParentSession.Permissionsto theSubSessionConfiginagent_delegation.goandskill_runner.go.ToolsApproved: truefromRunAgent. Background tasks now correctly inherit both theToolsApprovedboolean and the granularPermissionsrules from their parent session.Security Impact
This is a strict security improvement. By passing the parent permissions down, the sub-sessions correctly integrate with the dispatcher's auto-deny logic:
Allowlists) run seamlessly.Ask) hit the dispatcher'sNonInteractivecheck and are safely auto-denied, preventing background agents from hanging or bypassing user consent.